import matplotlib as matplotlib
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
import matplotlib

matplotlib.rcParams['font.sans-serif'] = ['FangSong']  # 指定默认字体
matplotlib.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题

class GrayForecast():
#初始化
    def __init__(self, data, datacolumn=None):
        print('init...')
        if isinstance(data, pd.core.frame.DataFrame):
            self.data = data
            try:
                self.data.columns = ['Sale Count']
            except:
                if not datacolumn:
                    raise Exception('您传入的dataframe不止一列')
                else:
                    self.data = pd.DataFrame(data[datacolumn])
                    self.data.columns = ['Sale Count']
        elif isinstance(data, pd.core.series.Series):
            self.data = pd.DataFrame(data, columns=['Sale Count'])
        else:
            self.data = pd.DataFrame(data, columns=['Sale Count'])

        self.forecast_list = self.data.copy()
        #print(self.data)

        if datacolumn:
            self.datacolumn = datacolumn
        else:
            self.datacolumn = None

        # save arg:
        #        data                DataFrame    数据
        #        forecast_list       DataFrame    预测序列
        #        datacolumn          string       数据的含义

    #级比校验
    def level_check(self):
        # 数据级比校验
        n = len(self.data)
        lambda_k = np.zeros(n - 1)
        for i in range(n - 1):
            lambda_k[i] = self.data.ix[i]['Sale Count'] / self.data.ix[i + 1]['Sale Count']
            if lambda_k[i] < np.exp(-2 / (n + 1)) or lambda_k[i] > np.exp(2 / (n + 2)):
                flag = False
        else:
            flag = True

        self.lambda_k = lambda_k

        if not flag:
            print("级比校验失败，请对X(0)做平移变换")
            return False
        else:
            print("级比校验成功，请继续")
            return True

        # save arg:
        #        lambda_k            1-d list

    #GM(1,1)建模
    def GM_11_build_model(self, forecast=5):
        if forecast > len(self.data):
            raise Exception('您的数据行不够')
        X_0 = np.array(self.forecast_list['Sale Count'].tail(forecast))
        #       1-AGO
        X_1 = np.zeros(X_0.shape)
        for i in range(X_0.shape[0]):
            X_1[i] = np.sum(X_0[0:i + 1])
        #       紧邻均值生成序列
        Z_1 = np.zeros(X_1.shape[0] - 1)
        for i in range(1, X_1.shape[0]):
            Z_1[i - 1] = -0.5 * (X_1[i] + X_1[i - 1])

        B = np.append(np.array(np.mat(Z_1).T), np.ones(Z_1.shape).reshape((Z_1.shape[0], 1)), axis=1)
        Yn = X_0[1:].reshape((X_0[1:].shape[0], 1))

        B = np.mat(B)
        Yn = np.mat(Yn)
        a_ = (B.T * B) ** -1 * B.T * Yn

        a, b = np.array(a_.T)[0]

        X_ = np.zeros(X_0.shape[0])

        def f(k):
            return (X_0[0] - b / a) * (1 - np.exp(a)) * np.exp(-a * (k))

        self.forecast_list.loc[len(self.forecast_list)] = f(X_.shape[0])

    #预测
    def forecast(self, time=5, forecast_data_len=5):
        for i in range(time):
            self.GM_11_build_model(forecast=forecast_data_len)
        print('forecast finished...')

    #打印日志
    def log(self,file_path):
        res = self.forecast_list.copy()
        print
        if self.datacolumn:
            res.columns = [self.datacolumn]
        res = res.astype(int)
        with open(file_path,'w') as file:
            for i in range(6):
                file.write('2024-0{}: '.format(i + 5) + '{}'.format(pd.DataFrame(self.forecast_list).values.tolist()[i+22]) + '\n')
        return res

    #重置
    def reset(self):
        self.forecast_list = self.data.copy()

    #作图
    def plot(self,used):
        if self.datacolumn:
            plt.plot(pd.date_range(start='2022-06', end='2024-11', freq='M'), self.forecast_list, label='未来值')
            plt.plot(pd.date_range(start='2022-06', end='2024-05', freq='M'), used, label='真实值')
            plt.xlabel('时间')
            plt.ylabel('销量')
            plt.title('销量及预测')
            plt.legend()
            plt.show()

if __name__ == '__main__':
    file_path = ['data/五菱car_sales_data.csv', 'data/广汽埃安car_sales_data.csv', 'data/比亚迪car_sales_data.csv',
                 'data/特斯拉car_sales_data.csv', 'data/理想car_sales_data.csv']
    pre_path = ['predict/五菱car_sales_data.txt', 'predict/广汽埃安car_sales_data.txt', 'predict/比亚迪car_sales_data.txt',
                 'predict/特斯拉car_sales_data.txt', 'predict/理想car_sales_data.txt']
    for i in range(5):
        f = open(file_path[i], encoding="latin1")
        df = pd.read_csv(f,encoding='latin1')
        df = df['Sale Count']
        df.tail()
        gf = GrayForecast(df, 'Sale Count')
        gf.forecast(6)
        gf.log(pre_path[i])
        #gf.plot(df)

